package com.qys.livesMall.aspect;

import com.alibaba.fastjson2.JSON;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.framework.utils.SecurityUtils;
import com.qys.livesMall.kafka.entity.log.SystemLog;
import com.qys.livesMall.kafka.send.KafkaClient;
import io.swagger.v3.oas.annotations.Operation;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * Created by IntelliJ IDEA.
 * User: dp
 * Date: 2023/06/05
 * Time: 15:16
 * DESCRIPTION: 后台用户操作日志
 */
@Slf4j
@Aspect
@Component
@EnableAspectJAutoProxy
public class SysUserLogAspect {

    @Resource
    private KafkaClient kafkaClient;


    @Pointcut("within(com.qys.livesMall..controller.sys..*)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint point) {
        log.info("开启后台管理的环绕通知");
        long start = System.currentTimeMillis();
        Object proceed;

        SystemLog systemLog = new SystemLog();
        systemLog.setUserName(SecurityUtils.getUsername());
        systemLog.setRecordTime(LocalDateTime.now());

        // 获取请求路径
        systemLog.setUrl(getRequestUrl());

        //方法名称
        Signature signature = point.getSignature();
        String objectMethod = signature.getDeclaringTypeName() + "." + signature.getName();

        try {
            Object[] args = point.getArgs();
            systemLog.setBeforeData(args);

            log.info("【环绕前置通知】【{}方法开始】,【方法参数:{}】", objectMethod, args);

            proceed = point.proceed();

            log.info("【环绕返回通知】【{}方法开始】,【方法返回值:{}】", objectMethod, JSON.toJSON(proceed));
            systemLog.setAfterData(proceed);
        } catch (Throwable e) {
            e.printStackTrace();
            systemLog.setEx(e.getMessage());
            if (e instanceof QysException ex) {
                throw new QysException(ex.getCode(), e.getMessage());
            }
            throw new QysException();
        } finally {
            log.info("【环绕通知：{} 结束】", objectMethod);
            long end = System.currentTimeMillis();

            systemLog.setTime(end - start);
        }

        //获取注解信息
        systemLog.setName(getSwaggerAnnotation(point));

        //发送消息
        kafkaClient.systemLog(systemLog);
        return proceed;
    }

    /**
     * 获取请求的url
     */
    private static String getRequestUrl() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = null;
        if (requestAttributes != null) {
            request = requestAttributes.getRequest();
        }
        if (request != null) {
            return request.getRequestURL().toString();
        }
        return null;
    }

    /**
     * 获取swagger注解的方法注释
     */
    private String getSwaggerAnnotation(ProceedingJoinPoint point) {
        MethodSignature ms = (MethodSignature) point.getSignature();
        Object target = point.getTarget();
        try {
            Method method = target.getClass().getMethod(ms.getName(), ms.getParameterTypes());
            Operation operation = method.getAnnotation(Operation.class);
            return null == operation ? null : operation.summary();
        } catch (Exception e) {
            log.error("【获取请求的swagger注释出错】");
        }
        return null;
    }

}
